package obstacle;

import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.util.ArrayList;

import Vue.Terrain;

import reseau.Coordonnees2D;
import reseau.Vecteur2D;

public class ObstaclePolygone implements IObstacle{
	
	protected ArrayList<Coordonnees2D> sommets;
	protected ArrayList<Ligne> aretes;
	
	protected int 	_redValue;
	protected int 	_greenValue;
	protected int 	_blueValue;
	protected ObstacleType _type;
	protected Terrain _terrain;
	@SuppressWarnings("unchecked")
	public ObstaclePolygone(ArrayList<Coordonnees2D> sommets)
	{
		this.sommets = (ArrayList<Coordonnees2D>) sommets.clone();
	}
	public ObstaclePolygone(ArrayList<Coordonnees2D> sommets, ObstacleType type, Terrain terrain)
	{
		this.sommets = (ArrayList<Coordonnees2D>) sommets.clone();
		this.aretes = new ArrayList<Ligne>();
		for(int i=0; i<this.sommets.size(); ++i)
			this.aretes.add(new Ligne(this.sommets.get(i),this.sommets.get((i+1)%this.sommets.size()), terrain));
		this._type=type;
		this._terrain= terrain;
		//this.setColot(r, g, b);
	}
	public ObstacleType getType()
	{
		return this._type;
	}
	protected void setColot(int r, int g, int b)
	{
		this._redValue = r;
		this._greenValue =g;
		this._blueValue =b;
	}
	public int getRedValue()
	{
		return this._redValue;
	}
	public int getGreenValue()
	{
		return this._greenValue;
	}
	public int getBlueValue()
	{
		return this._blueValue;
	}
	public boolean contient(Coordonnees2D point)
	{
		Polygon polygon = new Polygon();
		for(int i=0; i < this.sommets.size(); i++)
		{
			
			polygon.addPoint((int)this.sommets.get(i).getX(), (int)this.sommets.get(i).getY());
		}
		if(polygon.contains(point.getX(), point.getY()))
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	public ArrayList<Coordonnees2D> getSommets()
    {
    	return this.sommets;
    }
	
	public static Coordonnees2D intersection(Coordonnees2D seg1D,Coordonnees2D seg1A, Coordonnees2D seg2D, Coordonnees2D seg2A) 
	{
		double x1 = seg1D.getX();
		double x2 = seg1A.getX();
		
		double x3 = seg2D.getX();
		double x4 = seg2A.getX();
		
		double y1 = seg1D.getY();
		double y2 = seg1A.getY();
		
		double y3 = seg2D.getY();
		double y4 = seg2A.getY();
		
		double d = (x1-x2)*(y3-y4) - (y1-y2)*(x3-x4);
		if (d == 0) return null;
		
		double xi = ((x3-x4)*(x1*y2-y1*x2)-(x1-x2)*(x3*y4-y3*x4))/d;
		double yi = ((y3-y4)*(x1*y2-y1*x2)-(y1-y2)*(x3*y4-y3*x4))/d;
		
		Coordonnees2D p = new Coordonnees2D(xi,yi);
		if (xi < Math.min(x1,x2) || xi > Math.max(x1,x2)) return null;
		if (xi < Math.min(x3,x4) || xi > Math.max(x3,x4)) return null;
		if (yi < Math.min(y1,y2) || yi > Math.max(y1,y2)) return null;
        if (yi < Math.min(y3,y4) || yi > Math.max(y3,y4)) return null;
		return p;
	}
		
	@Override
	public Coordonnees2D getIntersection(Coordonnees2D depart, Coordonnees2D arrivee) 
	{
		Coordonnees2D intersect = null;
		float minDist = Integer.MAX_VALUE;
		
		for(int i = 0; i < this.sommets.size() - 1; i++)
		{
			Coordonnees2D pt = intersection(depart, arrivee, sommets.get(i), sommets.get(i + 1));
			if(pt == null)
				continue;
			float d = (float) Math.sqrt( Math.pow(pt.getX() - depart.getX(), 2.f) + Math.pow(pt.getY() - depart.getY(), 2.f));
			if(minDist > d)
			{
				minDist = d;
				intersect = pt;
			}
		}
		Coordonnees2D pt = intersection(depart, arrivee, sommets.get(this.sommets.size() - 1), sommets.get(0));
		if(pt == null)
			return (minDist == Integer.MAX_VALUE)? null:intersect;
	
		float d = (float) Math.sqrt( Math.pow(pt.getX() - depart.getX(), 2.f) + Math.pow(pt.getY() - depart.getY(), 2.f));
		if(minDist > d)
		{
			return pt;
		}
		return intersect;
	}

	@Override
	public Vecteur2D getVecteurTangent(Coordonnees2D depart, Coordonnees2D arrivee) 
	{
		/*float minDist = Integer.MAX_VALUE;
		Vecteur2D result = null;
		Vecteur2D vect = new Vecteur2D(arrivee.getX() - depart.getX(), arrivee.getY() - depart.getY());
		
		for(int i = 0; i < this.sommets.size() - 1; i++)
		{
			Coordonnees2D pt = intersection(depart, arrivee, sommets.get(i), sommets.get(i + 1));
			if(pt == null)
				continue;
			float d = (float) Math.sqrt( Math.pow(pt.getX() - depart.getX(), 2.f) + Math.pow(pt.getY() - depart.getY(), 2.f));
			if(minDist > d)
			{
				minDist = d;
				
				Vecteur2D v1 = new Vecteur2D(sommets.get(i).getX() - sommets.get(i + 1).getX(), sommets.get(i).getY() - sommets.get(i + 1).getY());
				Vecteur2D v2 = new Vecteur2D(sommets.get(i+1).getX() - sommets.get(i).getX(), sommets.get(i+1).getY() - sommets.get(i).getY());
				
				//on calcul le produit scalaire
				double pv1 = v1.getX() * vect.getX() + v1.getY() * vect.getY();
				double pv2 = v2.getX() * vect.getX() + v2.getY() * vect.getY();
				
				//on choisit le meilleur vecteur : celui qui a un produit scalaire negatif
				if(pv1 < 0)
					result = v1;
				if(pv2 < 0)
					result = v2;
			}
		}
		
		Coordonnees2D pt = intersection(depart, arrivee, sommets.get(this.sommets.size() - 1), sommets.get(0));
		if(pt == null)
		{
			return result;
		}
	
		float d = (float) Math.sqrt( Math.pow(pt.getX() - depart.getX(), 2.f) + Math.pow(pt.getY() - depart.getY(), 2.f));
		if(minDist > d)
		{
			Vecteur2D v1 = new Vecteur2D(sommets.get(sommets.size() - 1).getX() - sommets.get(0).getX(), sommets.get(sommets.size() - 1).getY() - sommets.get(0).getY());
			Vecteur2D v2 = new Vecteur2D(sommets.get(0).getX() - sommets.get(sommets.size() - 1).getX(), sommets.get(0).getY() - sommets.get(sommets.size() - 1).getY());
			
			//on calcul le produit scalaire
			double pv1 = v1.getX() * vect.getX() + v1.getY() * vect.getY();
			double pv2 = v2.getX() * vect.getX() + v2.getY() * vect.getY();
			
			//on choisit le meilleur vecteur : celui qui a un produit scalaire negatif
			if(pv1 < 0)
				result = v1;
			if(pv2 < 0)
				result = v2;
		}
		
		return result;*/
		Vecteur2D vecteurTangent = null;
		for(Ligne arete : this.aretes)
			if((vecteurTangent = arete.getVecteurTangent(depart, arrivee))!=null)
				return vecteurTangent;
		
		return vecteurTangent;
	}
	@Override
	public void display(Graphics2D g) {
		// TODO Auto-generated method stub
		Point leftUp = new Point((int)getSommets().get(0).getX(),(int)getSommets().get(0).getY());
		Point rightDown = new Point(leftUp);
		Polygon polygon = new Polygon();
		polygon.addPoint(leftUp.x, leftUp.y);
		for(int j=1; j<getSommets().size(); j++)
		{
			polygon.addPoint((int)getSommets().get(j).getX(),(int)getSommets().get(j).getY());
			if((int)getSommets().get(j).getX() < leftUp.getX())
			{
				leftUp.x = (int)getSommets().get(j).getX();
			}
			if((int)getSommets().get(j).getY() < leftUp.getY())
			{
				leftUp.y = (int)getSommets().get(j).getY();
			}
			if((int)getSommets().get(j).getX() > rightDown.getX())
			{
				rightDown.x = (int)getSommets().get(j).getX();
			}
			if((int)getSommets().get(j).getY() > rightDown.getY())
			{
				rightDown.y = (int)getSommets().get(j).getY();
			}
		}
		for(int px=leftUp.x; px <= rightDown.x; px++)
		{
			for(int py=leftUp.y; py <= rightDown.y; py++)
			{
				if(polygon.contains(px, py))
				{
					//System.out.println("r:"+obs.getRedValue()+"  g:"+obs.getGreenValue()+"  b:"+obs.getBlueValue());
					//this.setCellState(py, py, obs.getRedValue(), obs.getGreenValue(), obs.getBlueValue());
	    			this._terrain.initBuffer(px, py, getRedValue(), getGreenValue(), getBlueValue());					
				}
			}
		}
	}
	@Override
	public boolean tue() {
		// TODO Auto-generated method stub
		return false;
	}	
}
